package org.lemon.cla.exception.handler;
import com.auth0.jwt.exceptions.JWTDecodeException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.lemon.cla.dto.response.ResponseResult;
import org.lemon.cla.enums.HttpStatusEnum;
import org.lemon.cla.exception.BusinessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {



    // --- 专门处理权限不足异常 ---
    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN) // 返回 403 Forbidden
    public ResponseResult<?> handleAccessDeniedException(AccessDeniedException ex) {
//        log.warn("权限不足: {}", ex.getMessage()); // 记录权限不足日志
        return ResponseResult.fail(HttpStatusEnum.FORBIDDEN.getCode(), HttpStatusEnum.FORBIDDEN.getMessage());
    }

    /**
     * 处理自定义的业务异常 BusinessException
     * 当业务逻辑中主动抛出特定异常时捕获。
     * @param ex BusinessException 实例
     * @return 统一的错误结果 ResponseResult 对象，包含业务自定义的状态码和消息
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseResult<?> handleBusinessException(BusinessException ex) {
//        log.warn("Caught BusinessException: Code={}, Message={}", ex.getCode(), ex.getMessage());
        return ResponseResult.fail(ex.getCode(), ex.getMessage());
    }

    /**
     * 处理方法参数校验失败的异常 (例如 @Valid 或 @Validated 注解在 @RequestBody 上)
     * 当请求体中的数据不符合 DTO 的校验规则时触发。
     * @param ex MethodArgumentNotValidException 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 400 (BAD_REQUEST)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        // 获取第一个校验失败的字段的错误信息，提供给前端更具体的问题描述
        String errorMessage = ex.getBindingResult().getFieldError() != null ?
                ex.getBindingResult().getFieldError().getDefaultMessage() :
                HttpStatusEnum.BAD_REQUEST.getMessage(); // 如果没有具体错误消息，使用枚举的默认消息
//        log.warn("Caught MethodArgumentNotValidException: {}", errorMessage);
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(), errorMessage);
    }

    /**
     * 处理路径变量或请求参数类型不匹配的异常 (例如 /users/abc，而期望是 Long 类型ID)
     * 当 Spring 尝试将请求参数或路径变量转换为目标类型失败时触发。
     * @param ex MethodArgumentTypeMismatchException 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 400 (BAD_REQUEST)
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseResult<?> handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) {
        String paramName = ex.getName();
        String requiredType = ex.getRequiredType() != null ? ex.getRequiredType().getSimpleName() : "未知类型";
        String errorMessage = String.format("参数 '%s' 类型不匹配，期望类型为 '%s'。", paramName, requiredType);
//        log.warn("Caught MethodArgumentTypeMismatchException: {}", errorMessage);
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(), errorMessage);
    }

    /**
     * 处理请求体无法读取或解析的异常 (例如 JSON 格式错误或请求体为空)
     * 当 @RequestBody 无法被正确反序列化时触发。
     * @param ex HttpMessageNotReadableException 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 400 (BAD_REQUEST)
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseResult<?> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {
//        log.warn("Caught HttpMessageNotReadableException: 请求体格式不正确或为空。");
        ex.printStackTrace();
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(), "请求体格式不正确或为空，请检查JSON格式。");
    }

    /**
     * 处理文件上传时缺少必填文件部分的异常
     * 当 @RequestPart 标记的参数缺失时触发。
     * @param ex MissingServletRequestPartException 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 400 (BAD_REQUEST)
     */
    @ExceptionHandler(MissingServletRequestPartException.class)
    public ResponseResult<?> handleMissingServletRequestPartException(MissingServletRequestPartException ex) {
//        log.warn("Caught MissingServletRequestPartException: 文件上传请求中缺少必填部分 - {}", ex.getRequestPartName());
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(),
                "上传失败：请求中缺少文件或文件部分。请确保参数名为'" + ex.getRequestPartName() + "'且内容不为空。");
    }

    /**
     * 处理必需的 @RequestParam 参数缺失的异常
     * 当 URL 查询参数被标记为 required 但未提供时触发。
     * @param ex MissingServletRequestParameterException 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 400 (BAD_REQUEST)
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseResult<?> handleMissingServletRequestParameter(MissingServletRequestParameterException ex) {
        String errorMessage = String.format("缺少必需的请求参数 '%s'。", ex.getParameterName());
//        log.warn("Caught MissingServletRequestParameterException: {}", errorMessage);
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(), errorMessage);
    }

    /**
     * 处理使用 JSR303/JSR380 校验注解（如 @NotNull）在非请求体参数上失败的异常
     * 通常发生在对 @PathVariable 或 @RequestParam 直接进行校验时（需要在控制器类上加 @Validated）。
     * @param ex ConstraintViolationException 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 400 (BAD_REQUEST)
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseResult<?> handleConstraintViolationException(ConstraintViolationException ex) {
        // 提取第一个校验失败的字段的错误信息
        String errorMessage = ex.getConstraintViolations().iterator().next().getMessage();
//        log.warn("Caught ConstraintViolationException: {}", errorMessage);
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(), "请求参数校验失败: " + errorMessage);
    }


    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseResult<?> handleNoResourceFoundException(NoResourceFoundException ex) {
        return ResponseResult.fail(HttpStatusEnum.MIMADE.getCode(),HttpStatusEnum.MIMADE.getMessage());
    }
    /**
     * 处理 DAO 异常，通常是数据库约束
     * */
    @ExceptionHandler(DataIntegrityViolationException.class)
    public ResponseResult<?> handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
        return ResponseResult.fail(HttpStatusEnum.CONFLICT.getCode(),HttpStatusEnum.CONFLICT.getMessage(),"数据库操作被拒绝，请检查键值约束（类型、长度、唯一、外键、非空等）");
    }
    @ExceptionHandler(JWTDecodeException.class)
    public ResponseResult<?> handleJWTDecodeException(Exception ex) {
        
//        log.error("Caught unhandled exception: ", ex);
        return ResponseResult.fail(HttpStatusEnum.UNSUPPORTED_TYPE.getCode(), "token解析失败，检查token是否是64位编码字符串或token本身是否缺失");
    }
    @ExceptionHandler(BadCredentialsException.class)
    public ResponseResult<?> handleBadCredentialsException(Exception ex) {
//        log.error("Caught unhandled exception: ", ex);
        return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST.getCode(),"用户名或密码不正确");
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseResult<?> handleHttpRequestMethodNotSupportedException(Exception ex) {
//        log.error("Caught unhandled exception: ", ex);
        return ResponseResult.fail(HttpStatusEnum.BAD_METHOD.getCode(),HttpStatusEnum.BAD_METHOD.getMessage());
    }

    /**
     * 处理所有其他未被特定 @ExceptionHandler 捕获的通用异常
     * 这是最后一道防线，用于捕获所有未预料的系统错误，并返回 500 状态码。
     * @param ex Exception 实例
     * @return 统一的错误结果 ResponseResult 对象，状态码 500 (ERROR)
     */

    @ExceptionHandler(Exception.class)
    public ResponseResult<?> handleGeneralException(Exception ex) {
        
//        log.error("Caught unhandled exception: ", ex);
        return ResponseResult.fail(HttpStatusEnum.ERROR.getCode(), HttpStatusEnum.ERROR.getMessage());
    }

}